package cert_mgr

import (
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	logger "gitee.com/zaper/private-logger"
	"gitee.com/zaper/software-framework/constant"
	"github.com/youmark/pkcs8"
	"os"
	"strconv"
)

// GetServiceTlsConfig 双向认证，客户端服务端都要ca(服务端ClientCAs，客户端RootCAs)和服务证书
// GetServiceTlsConfig 单向认证，客户端要ca(RootCAs)，服务端要服务证书
func GetServiceTlsConfig() *tls.Config {
	srvTls := getServerCert()

	mode := getTlsMode()
	var verifyMode = tls.NoClientCert
	var caTls *x509.CertPool
	if mode == constant.Mutual {
		verifyMode = tls.RequireAndVerifyClientCert
		caTls = getCaCert()
	}

	return &tls.Config{
		Certificates: []tls.Certificate{*srvTls},
		ClientAuth:   verifyMode,
		ClientCAs:    caTls,
		MinVersion:   tls.VersionTLS12,
	}
}

func GetClientTlsConfig() *tls.Config {
	caTls := getCaCert()

	mode := getTlsMode()
	if mode == constant.Mutual {
		srvTls := getServerCert()
		return &tls.Config{
			Certificates: []tls.Certificate{*srvTls},
			RootCAs:      caTls,
			MinVersion:   tls.VersionTLS12,
		}
	}
	return &tls.Config{
		RootCAs:    caTls,
		MinVersion: tls.VersionTLS12,
	}
}

func getTlsMode() int {
	tlsMode := os.Getenv(constant.TlsMode)
	if tlsMode == "" {
		return constant.Mutual
	}
	mode, err := strconv.ParseInt(tlsMode, 10, 32)
	if err != nil {
		return constant.Mutual
	}
	if mode == constant.Oneway {
		return constant.Oneway
	} else {
		return constant.Mutual
	}
}

func getServerCert() *tls.Certificate {
	// 1. 读取加密的私钥文件
	certPEM, err := os.ReadFile(fmt.Sprintf("%s%s", os.Getenv(constant.SslPath), constant.PublicServer))
	if err != nil {
		logger.Errorf("read cert fail: %s", err)
		return nil
	}
	keyPEM, err := os.ReadFile(fmt.Sprintf("%s%s", os.Getenv(constant.SslPath), constant.PrivateServer))
	if err != nil {
		logger.Errorf("read private fail: %s", err)
		return nil
	}
	block, _ := pem.Decode(keyPEM)
	password := []byte(os.Getenv(constant.SslPwd))
	privateKey, err := pkcs8.ParsePKCS8PrivateKey(block.Bytes, password)
	if err != nil {
		logger.Errorf("parse privateKey fail: %s", err)
		return nil
	}
	// 4. 转换为 PEM 格式（如果是 RSA 私钥）
	privateKeyPEM := pem.EncodeToMemory(&pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(privateKey.(*rsa.PrivateKey)),
	})
	cert, err := tls.X509KeyPair(
		certPEM,
		privateKeyPEM,
	)
	return &cert
}

func getCaCert() *x509.CertPool {
	// 5. 加载CA证书（用于验证客户端证书）
	caPath := fmt.Sprintf("%s%s", os.Getenv(constant.SslPath), constant.PublicCa) // 假设CA证书路径常量
	caPEM, err := os.ReadFile(caPath)
	if err != nil {
		logger.Errorf("read ca fail: %s", err)
		return nil
	}

	certPool := x509.NewCertPool()
	if !certPool.AppendCertsFromPEM(caPEM) {
		logger.Error("parse ca fail")
		return nil
	}
	return certPool
}
